#include <iostream>
#include "ServerSocket.h"

#include "SocketHandler.h"
using namespace yazi::socket;

#include "AutoLock.h"
#include "Task.h"
#include "TaskDispatcher.h"
using namespace yazi::thread;

#include "TaskFactory.h"
using namespace yazi::task;

#include "Singleton.h"
#include "Logger.h"
#include "ObjectPool.h"
using namespace yazi::utility;


SocketHandler::SocketHandler(){

}

SocketHandler::~SocketHandler(){
    if(m_epoll != NULL){
        delete m_epoll;
        m_epoll = NULL;
    }
    if(m_server != NULL){
        delete m_server;
        m_server = NULL;
    }
}


void SocketHandler::listen(const string &ip, const int port){
    m_server = new ServerSocket(ip, port);
}

void SocketHandler::attach(Socket *sock)
{
    AutoLock lock(&m_mutex);
    m_epoll->add(sock->m_sockfd, (void*)sock, EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLONESHOT);
}

void SocketHandler::detach(Socket* sock){
    AutoLock lock(&m_mutex);
    m_epoll->del(sock->m_sockfd, (void *)sock, EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLONESHOT);
}

void SocketHandler::remove(Socket* sock){
    AutoLock lock(&m_mutex);
    sock->close();
    m_sockpool.release(sock);
}

void SocketHandler::handle(int maxconnections, int millseconds){
    m_epoll = new EventPoller(false);
    m_epoll->create(maxconnections);
    m_epoll->add(m_server->m_sockfd, (void*)m_server, (EPOLLIN | EPOLLHUP | EPOLLERR));
    m_sockpool.init(maxconnections);

    std::cout << "epoll wait time: " << millseconds << " ms " << endl;
    while(1){
        int num = m_epoll->wait(millseconds);
        if(num == 0){
            // std::cout << "no events" << endl;
            continue;
        }
        for (int i = 0; i < num; ++i)
        {
            Socket *cursock = static_cast<Socket *>(m_epoll->m_events[i].data.ptr);
            if (cursock == m_server)
            {
                std::cout << "sock accpet events" << endl;
                int connfd = -1;
                if ((connfd = cursock->accept()) == -1)
                    return;
                Socket *psock = m_sockpool.allocate();
                if(!psock){
                    std::cerr << "socket pool is empty" << endl;
                    break;
                }
                psock->m_sockfd = connfd;
                psock->set_nonblock();
                attach(psock);
            }
            else {
                if(m_epoll->m_events[i].events & EPOLLERR){
                    std::cerr << "socket " << cursock->m_sockfd << " error" << endl;
                    detach(cursock);
                    remove(cursock);
                }
                else if(m_epoll->m_events[i].events & EPOLLHUP){
                    std::cerr << "socket " << cursock->m_sockfd << " closed" << endl;
                    detach(cursock);
                    remove(cursock);
                }
                else if(m_epoll->m_events[i].events & EPOLLIN){
                    std::cout << "socket read events" << endl;
                    detach(cursock);
                    Task* task = Singleton<TaskFactory>::instance()->create(cursock);
                    Singleton<TaskDispatcher>::instance()->assign(task);
                }
            }
        }
    }
}

